<?php

/**
 * The Plugin Manager class. Plugin Manager is responsible for enabling and disabling plugins
 * as well as to parse their XML files and dispatch all the plugin common events
 */
class PluginManager {
	/**
	 * Registry of all the plugin instances
	 */
	protected $instances;

	/**
	 * Default constructor. Autoloads the enabled plugins
	 */
	public function __construct() {
		$this->instances = array();
		
		// load abstract plugin class
		Cinnamon::loadClass('AbstractPlugin');
		
		// autoload enabled plugins
		$plugins = Cinnamon::registry('config')->get('plugins.enabled');
		foreach ( (array) $plugins as $pluginId ) {
			$this->load($pluginId);
		}
	}
	
	/**
	 * Enables the plugin with the specified ID. Please note that the id defined in the XML file
	 * must be identical to the folder name.
	 *
	 * @param string pluginId the plugin id to be enabled
	 */
	public function enable($pluginId) {
		$this->load($pluginId);
		
		$config = Cinnamon::registry('config');
		
		// update the enabled plugins at the configuration
		$enabledPlugins = $config->get('plugins.enabled');
		array_push($enabledPlugins, $pluginId);
		$config->set('plugins.enabled', $enabledPlugins);
					
		// dispatch 'enable' plugin event
		$this->callPluginMethod($pluginId, 'enable');	
	}
	
	/**
	 * Disables the plugin with the specified ID. Please note that the id defined in the XML file
	 * must be identical to the folder name.
	 *
	 * @param string pluginId the plugin id to be disabled
	 */	
	public function disable($pluginId) {
		$config = Cinnamon::registry('config');
	
		// update the enabled plugins at the configuration
		$enabledPlugins = $config->get('plugins.enabled');
		$enabledPlugins = array_remove($enabledPlugins, $pluginId);
		$config->set('plugins.enabled', $enabledPlugins);	
		
		// dispatch 'disable' plugin event
		$this->callPluginMethod($pluginId, 'disable');		
	}
	
	/**
	 * Returns true if the specified plugin is enabled
	 */
	public function isEnabled($pluginId) {
		$plugins = Cinnamon::registry('config')->get('plugins.enabled');
		return ( in_array($pluginId, $plugins) );
	}	 
	
	/**
	 * Returns the instances of the enabled plugins
	 * 
	 * @return associative array an array which containes the instances of the enabled plugins
	 */
	public function getAllInstances() {
		return $this->instances;
	}
	
	/**
	 * Returns the instance of the specified plugin. If that plugin is not enabled null will be returned.
	 */
	public function getInstanceOf($pluginId) {
		return $this->instances[$pluginId];
	}
	
	/**
	 * Returns the available plugins and their details
	 */
	public function getAllPlugins() {
		$plugins = array();
		$xmlfiles = glob(CSEPATH .'/plugins/*/plugin.xml');
		if ( is_array($xmlfiles) && count($xmlfiles) > 0 ) {
			foreach ( $xmlfiles as $xmlfile ) {
				$plugins[] = $this->parsePluginXMLFile($xmlfile);
			}
		}
		return $plugins;
	}
	
	/**
	 * Returns the available details for the specified plugin
	 */
	public function getPlugin($pluginId) {
		$xmlfile = CSEPATH .'/plugins/'. $pluginId .'/plugin.xml';
		return $this->parsePluginXMLFile($xmlfile);
	}
	
	protected function parsePluginXMLFile($file) {
		// create document and XPath instances 
		$dom = new DOMDocument();
		$dom->load($file);
		$xpath = new DOMXPath($dom);
		
		$plugin = new stdClass();
		
		// plugin unique identifier and version
		$item = $xpath->query('/cseplugin/plugin')->item(0);
		$plugin->id = $item->getAttribute('id');
		$plugin->version = $item->getAttribute('version');
		unset($item);
		
		// plugin title and description
		$plugin->title = $xpath->query('/cseplugin/plugin/title/text()')->item(0)->data;
		$plugin->description = $xpath->query('/cseplugin/plugin/description/text()')->item(0)->data;		
		
		// plugin cseversion 
		$item = $xpath->query('/cseplugin/version')->item(0);
		$plugin->minVersion = $item->getAttribute('min');
		$plugin->maxVersion = $item->getAttribute('max');
		
		// plugin filters
		$plugin->filters = $xpath->query('/cseplugin/filters/filter');				
		
		// is that plugin enabled or disabled?
		$plugin->isEnabled = $this->isEnabled($plugin->id);				
		
		return $plugin;
	}
	
	//
	// Load functions
	//
	protected function load($pluginId) {
		$pluginId = basename($pluginId);
		$file = CSEPATH .'/plugins/'. $pluginId .'/plugin.php';
		
		if ( !file_exists($file) ) {
			return;
		}

		require_once $file;
		$class = $pluginId .'Plugin';
		$class = str_replace('-', '', $class);
		if ( class_exists($class) ) {
			$this->instances[$pluginId] = new $class();
		}
	}
	
	//
	//
	//
	protected function callPluginMethod($pluginId, $method) {
		$instance = $this->getInstanceOf($pluginId);
		if ( $instance == null ) {
			return; 
		}
		
		if ( method_exists($instance, $method) && is_subclass_of($instance, 'AbstractPlugin') ) {
			call_user_func(array($instance, $method));
		}
	}

}
?>